﻿using Airthmetic;
using BaseTool;
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Text;
using System.Windows.Forms;

namespace StructuredLightSystemUI
{
    /// <summary>
    /// 投影仪测试页面
    /// </summary>
    public partial class ConProjector : UserControl
    {
        /// <summary> 投影仪工具 </summary>
        private ProjectorTool tool { get { return MyGlobal.ProjectorTool; } }
        /// <summary> 图像列表 </summary>
        public List<ProjectorImageMessage> ImageList { get { return tool.Param.proImageList; } }

        /// <summary> 正在刷新控件 </summary>
        private bool isRefreshControl_Port = false;
        /// <summary> 正在刷新控件 </summary>
        private bool isRefreshControl_Projector = false;
        /// <summary> 正在刷新控件 </summary>
        private bool isRefreshControl_DataGridView = false;

        #region 构造、初始化
        /// <summary>
        /// 构造
        /// </summary>
        public ConProjector()
        {
            InitializeComponent();
        }

        //加载时
        private void ConProjector_Load(object sender, EventArgs e)
        {
            Machine.ChangeProductAction += RefreshControl;
        }

        /// <summary> 打开用户控件 </summary>
        public void OpenControl()
        {
            RefreshControl();
            timer1.Enabled = true;
        }
        /// <summary> 关闭用户控件 </summary>
        public void CloseControl()
        {
            timer1.Enabled = false;
        }
        #endregion

        /// <summary>
        /// 刷新窗体信息
        /// </summary>
        private void RefreshControl()
        {
            //刷新串口信息
            RefreshPort(true);
            //刷新图像列表
            RefreshDataGridView(false);
        }

        #region 串口设置
        /// <summary>
        /// 刷新串口信息
        /// </summary>
        private void RefreshPort(bool isRefreshData)
        {
            isRefreshControl_Port = true;
            try
            {
                //数据加载
                if (isRefreshData)
                {
                    //空加载
                    if (cb_Port.Items == null || cb_Port.Items.Count == 0)
                    {
                        cb_Port.Items.Clear();
                        cb_Port.Items.AddRange(tool.GetPortNames().ToArray());
                    }
                    if (cb_BaudRate.Items == null || cb_BaudRate.Items.Count == 0)
                        cb_BaudRate.Items.AddRange(tool.Param.serialPortParam.ConstBaudRate);
                    if (cb_Parity.Items == null || cb_Parity.Items.Count == 0)
                        cb_Parity.Items.AddRange(Enum.GetNames(typeof(Parity)));
                    if (cb_DataBit.Items == null || cb_DataBit.Items.Count == 0)
                        cb_DataBit.Items.AddRange(tool.Param.serialPortParam.ConstDataBit);
                    if (cb_StopBit.Items == null || cb_StopBit.Items.Count == 0)
                        cb_StopBit.Items.AddRange(Enum.GetNames(typeof(StopBits)));

                    //数据赋值
                    cb_Port.Text = tool.Param.serialPortParam.PortName;
                    cb_BaudRate.Text = tool.Param.serialPortParam.BaudRate.ToString();
                    cb_Parity.Text = tool.Param.serialPortParam.Parity.ToString();
                    cb_DataBit.Text = $"{tool.Param.serialPortParam.DataBits}bit";
                    cb_StopBit.Text = tool.Param.serialPortParam.StopBits.ToString();
                }

                //使能
                bool isOpen = tool.IsOpen;
                cb_Port.Enabled = !isOpen;
                cb_BaudRate.Enabled = !isOpen;
                cb_Parity.Enabled = !isOpen;
                cb_DataBit.Enabled = !isOpen;
                cb_StopBit.Enabled = !isOpen;
                b_Open.Text = isOpen ? "关闭串口" : "打开串口";
                b_Open.BackColor = isOpen ? Color.Red : Color.Green;

                //刷新投影仪参数
                RefreshProjector();
            }
            catch (Exception ex)
            {
                Log.SaveError(ex);
            }
            finally
            {
                isRefreshControl_Port = false;
            }
        }
        //添加串口号
        private void cb_Port_DropDown(object sender, EventArgs e)
        {
            cb_Port.Items.Clear();
            cb_Port.Items.AddRange(tool.GetPortNames().ToArray());
        }
        //串口信息修改
        private void cb_TextChanged(object sender, EventArgs e)
        {
            if (isRefreshControl_Port)
                return;

            try
            {
                tool.Param.serialPortParam.PortName = cb_Port.Text;
                tool.Param.serialPortParam.BaudRate = int.Parse(cb_BaudRate.Text);
                tool.Param.serialPortParam.Parity = (Parity)Enum.Parse(typeof(Parity), cb_Parity.Text);
                tool.Param.serialPortParam.DataBits = int.Parse(cb_DataBit.Text.Replace("bit", ""));
                tool.Param.serialPortParam.StopBits = (StopBits)Enum.Parse(typeof(StopBits), cb_StopBit.Text);

                tool.Save();
            }
            catch (Exception ex)
            {
                //作者备注：理论不会进入
                Log.SaveError(ex, $"串口参数设置异常，{ex.Message}", LogType.Run);
                RefreshPort(true);
            }
        }
        //打开/关闭串口
        private void b_Open_Click(object sender, EventArgs e)
        {
            try
            {
                if (tool.IsOpen)
                    tool.Close();
                else
                    tool.Open();

                //刷新串口
                RefreshPort(false);
            }
            catch (Exception ex)
            {
                //作者备注：理论不会进入
                Log.SaveError(ex, $"串口操作异常，{ex.Message}", LogType.Run);
            }
        }
        #endregion

        #region 投影仪相关刷新
        /// <summary>
        /// 刷新投影仪
        /// </summary>
        private void RefreshProjector()
        {
            isRefreshControl_Projector = true;
            try
            {
                //连接状态切换修改内容
                bool isOpen = tool.IsOpen;
                if (!isOpen)
                {
                    cb_switchLed.Checked = false;
                    cb_switchLed.Text = "开/关灯";
                    cb_workPattern.Checked = false;
                    cb_workPattern.Text = "测试模式/普通模式";
                    cb_autoPower.Checked = false;
                    cb_autoPower.Text = "自动断电/不自动断电";
                    nud_brightness.Value = 10;
                }
                //连接状态切换修改内容
                gb_proBasicSetting.Enabled = isOpen;
                gb_proShowOne.Enabled = isOpen;
                gb_proShowMult.Enabled = isOpen;
                gb_proImageWrite.Enabled = isOpen;

                //控件一次性添加内容 - 图片写入
                if (cb_WriteSelect.Items.Count == 0)
                    cb_WriteSelect.Items.AddRange(GetImageNames());
                //控件一次性添加内容 - 单张图像播放
                if (cb_SelectShow.Items.Count == 0)
                    cb_SelectShow.Items.AddRange(GetImageNames());
            }
            catch (Exception ex)
            {
                Log.SaveError(ex);
            }
            finally
            {
                isRefreshControl_Projector = false;
            }
        }
        /// <summary>
        /// 刷新图像列表
        /// </summary>
        /// <param name="isReset">重置图像列表</param>
        private void RefreshDataGridView(bool isReset = false)
        {
            isRefreshControl_DataGridView = true;
            try
            {
                //重置图像列表
                if (isReset ||
                    ImageList == null || ImageList.Count != 256)
                    tool.Param.ResetImageList();

                //清空全部数据
                if (dgv.Rows.Count != ImageList.Count)
                    dgv.Rows.Clear();

                //添加全部数据
                dgv.Rows.Add(ImageList.Count);
                for (int i = 0; i < ImageList.Count; i++)
                {
                    dgv[0, i].Value = ImageList[i].Index + 1;
                    dgv[1, i].Value = ImageList[i].IndexHex;
                    dgv[2, i].Value = ImageList[i].DefaultText;
                    dgv[3, i].Value = ImageList[i].Remark;
                }
            }
            catch (Exception ex)
            {
                Log.SaveError(ex);
            }
            finally
            {
                isRefreshControl_DataGridView = false;
            }
        }

        //单元格点击
        private void dgv_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            try
            {
                //按钮事件
                switch (e.ColumnIndex)
                {
                    //显示图像
                    case 4:
                        {
                            byte index = (byte)((int)dgv[0, e.RowIndex].Value - 1);
                            if (ImageList[index].ImageIsEmpty)
                            {
                                Log.SaveLog($"[{GetImageName(index)}] 未写入图片，无法显示", LogType.Run, Color.Red);
                                break;
                            }

                            ImageForm imageForm = new ImageForm(
                                ImageTool.GetFullImage(
                                    ImageList[index].ImageData,
                                    ImageList[index].ImageWidth,
                                    ImageList[index].ImageHeight));
                            imageForm.Text = $"图像数据显示 - {GetImageName(index)}";
                            imageForm.Show();
                            break;
                        }
                    //重新写入
                    case 5:
                        {
                            byte index = (byte)((int)dgv[0, e.RowIndex].Value - 1);
                            if (ImageList[index].ImageIsEmpty)
                            {
                                Log.SaveLog($"[{GetImageName(index)}] 未写入图片，无法重新写入", LogType.Run, Color.Red);
                                break;
                            }

                            ImageWriteToProjector(index, false, true);
                            break;
                        }
                }
            }
            catch (Exception ex)
            {
                Log.SaveError(ex);
            }
        }
        //单元格选择切换
        private void dgv_SelectionChanged(object sender, EventArgs e)
        {
            if (isRefreshControl_DataGridView)
                return;
            try
            {
                if (dgv.SelectedCells == null || dgv.SelectedCells.Count <= 0)
                    return;

                //选中重新写入播放
                if (cb_GridSelectWriteShow.Checked)
                {
                    byte index = (byte)((int)dgv[0, dgv.SelectedCells[0].RowIndex].Value - 1);
                    if (ImageList[index].ImageIsEmpty)
                    {
                        Log.SaveLog($"[{GetImageName(index)}] 未写入图片，无法重新写入", LogType.Run, Color.Red);
                        return;
                    }
                    //重新写入
                    ImageWriteToProjector(index, false, true);
                    //播放
                    ProjectorShowOne(index);
                }
                //单张图片播放
                else if (cb_GridSelectShow.Checked)
                {
                    byte index = (byte)((int)dgv[0, dgv.SelectedCells[0].RowIndex].Value - 1);
                    //播放
                    ProjectorShowOne(index);
                }
            }
            catch (Exception ex)
            {
                Log.SaveError(ex);
            }
        }
        //单元格重置
        private void 重置ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                //重置
                tool.Param.ResetImageList();
                //保存数据
                tool.Save();
                //刷新表格
                RefreshDataGridView();
            }
            catch (Exception ex)
            {
                Log.SaveError(ex);
            }
        }

        #endregion

        #region 投影仪 - 基础控制
        //开/关灯
        private void cb_switchLed_CheckedChanged(object sender, EventArgs e)
        {
            if (isRefreshControl_Projector)
                return;

            bool isOpen = cb_switchLed.Checked;
            string msg = isOpen ? "开灯" : "关灯";
            try
            {
                cb_switchLed.Text = msg;
                tool.Send(tool.GetData_SwitchLED(cb_switchLed.Checked));
            }
            catch (Exception ex)
            {
                Log.SaveError(ex, $"投影仪{msg}异常，{ex.Message}", LogType.Run);
            }
        }
        //测试模式/普通模式  自动断电/不自动断电
        private void cb_workPattern_CheckedChanged(object sender, EventArgs e)
        {
            if (isRefreshControl_Projector)
                return;

            bool isTestMode = cb_workPattern.Checked;
            bool isAutoPower = cb_autoPower.Checked;
            try
            {
                cb_workPattern.Text = isTestMode ? "测试模式" : "普通模式";
                cb_autoPower.Text = isAutoPower ? "自动断电" : "不自动断电";
                tool.Send(tool.GetData_WorkPattern(isTestMode, isAutoPower));
            }
            catch (Exception ex)
            {
                Log.SaveError(ex, $"投影仪工作模式异常，{ex.Message}", LogType.Run);
            }
        }
        //亮度
        private void nud_brightness_ValueChanged(object sender, EventArgs e)
        {
            if (isRefreshControl_Projector)
                return;

            try
            {
                tool.Send(tool.GetData_BrightnessSetting((byte)nud_brightness.Value));
            }
            catch (Exception ex)
            {
                Log.SaveError(ex, $"投影仪设置亮度异常，{ex.Message}", LogType.Run);
            }
        }
        #endregion

        #region 投影仪 - 图片写入
        //单张图片写入
        private void b_WriteOne_Click(object sender, EventArgs e)
        {
            if (cb_WriteSelect.SelectedIndex < 0)
                return;
            ImageWriteToProjector((byte)cb_WriteSelect.SelectedIndex, false);
        }
        //多张图片写入
        private void b_WriteMult_Click(object sender, EventArgs e)
        {
            if (cb_WriteSelect.SelectedIndex < 0)
                return;
            ImageWriteToProjector((byte)cb_WriteSelect.SelectedIndex, true);
        }
        //单张图片写入
        private void 单张图片写入ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (dgv.SelectedCells == null || dgv.SelectedCells.Count <= 0)
                return;
            byte index = (byte)((int)dgv[0, dgv.SelectedCells[0].RowIndex].Value - 1);
            ImageWriteToProjector(index, false);
        }
        //多张图片写入
        private void 多张图片写入ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (dgv.SelectedCells == null || dgv.SelectedCells.Count <= 0)
                return;
            byte index = (byte)((int)dgv[0, dgv.SelectedCells[0].RowIndex].Value - 1);
            ImageWriteToProjector(index, true);
        }

        /// <summary>
        /// 图片写入投影仪
        /// </summary>
        /// <param name="start"> 开始索引 </param>
        /// <param name="isMult"> 是否多选 </param>
        /// <param name="isRepeated"> 是否重复写入 </param>
        private void ImageWriteToProjector(byte start, bool isMult, bool isRepeated = false)
        {
            try
            {
                //重复写入
                if (isRepeated)
                {
                    tool.Send(tool.GetData_GenStripe(
                        ImageList[start].ImageData,
                        start,
                        ImageList[start].ImageWidth,
                        ImageList[start].ImageHeight));

                    Log.SaveLog($"[{GetImageName(start)}] 写入投影仪成功", LogType.Run, Color.Black);
                    return;
                }
                else
                {
                    //选择文件
                    OpenFileDialog ofd = new OpenFileDialog();
                    ofd.InitialDirectory = PathTool.DataPatternImagePath;
                    ofd.Multiselect = isMult;
                    ofd.Filter = "(图片文件)|*.bmp;*.jpg;*.png|(*.*)|*.*";
                    if (ofd.ShowDialog() != DialogResult.OK)
                        return;

                    //再次询问
                    StringBuilder sb = new StringBuilder();
                    sb.AppendLine($"是否将 {ofd.FileNames.Length} 个图片数据写入到投影仪中？");
                    for (int i = 0; i < ofd.FileNames.Length; i++)
                    {
                        FileInfo fi = new FileInfo(ofd.FileNames[i]);
                        sb.AppendLine($"{GetImageName(start + i)} <--- \\\\" + fi.Name);
                    }

                    if (MessageBox.Show(sb.ToString(), "提示", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information) != DialogResult.Yes)
                        return;

                    //写入投影仪
                    for (int i = 0; i < ofd.FileNames.Length; i++)
                    {
                        byte index = (byte)(start + i);
                        try
                        {
                            Mat image = Cv2.ImRead(ofd.FileNames[i], ImreadModes.Grayscale);

                            if ((image.Width != 960 && image.Width != 1) ||
                                (image.Height != 540 && image.Height != 1))
                            {
                                Log.SaveLog($"[{GetImageName(index)}] 写入投影仪失败，仅能传入960*540、960*1、1*540的图片", LogType.Run, Color.Red);
                                continue;
                            }

                            //写入投影仪
                            tool.Send(tool.GetData_GenStripe(image, index, false));

                            //写入保存参数中
                            ImageList[index].Remark = new FileInfo(ofd.FileNames[i]).Name;
                            ImageList[index].ImageData = tool.GenStripe(image);
                            ImageList[index].ImageWidth = 960;
                            ImageList[index].ImageHeight = 540;

                            Machine.StatusBarAction?.Invoke(1.0 * (i + 1) / (ofd.FileNames.Length), $"写入图片：{i + 1} / {ofd.FileNames.Length}", Color.Black);
                            Log.SaveLog($"[{GetImageName(index)}] 写入投影仪成功", LogType.Run, Color.Black);
                        }
                        catch (Exception ex2)
                        {
                            Log.SaveError(ex2, $"[{GetImageName(index)}] 写入投影仪异常，{ex2.Message}", LogType.Run);
                        }
                        //GetParent(this, 5).Refresh();
                    }

                    //保存数据
                    tool.Save();
                    //刷新表格
                    RefreshDataGridView();
                }
            }
            catch (Exception ex)
            {
                Log.SaveError(ex, $"写入图片异常，{ex.Message}", LogType.Run);
            }
        }

        #endregion

        #region 投影仪 - 图像播放
        //单张图片播放 - 下拉框切换
        private void cb_SelectShow_SelectedIndexChanged(object sender, EventArgs e)
        {
            ProjectorShowOne(cb_SelectShow.SelectedIndex);
        }
        /// <summary>
        /// 单张图片播放
        /// </summary>
        /// <param name="index"></param>
        private void ProjectorShowOne(int index)
        {
            try
            {
                tool.Send(tool.GetData_DisplayImage((byte)index));
            }
            catch (Exception ex)
            {
                Log.SaveError(ex, $"投影仪单张图片播放异常，{ex.Message}", LogType.Run);
            }
        }

        //多张图像连续播放 - 参数变更
        private void nud_ShowMult_ValueChanged(object sender, EventArgs e)
        {
            byte start = (byte)((int)nud_showMultStart.Value - 1);
            ProjectorFrame frame = new ProjectorFrame((int)nud_showMultFrequency.Value);
            nud_showMultCount.Maximum = 256 - (int)nud_showMultFrequency.Value + 1;
            byte count = (byte)nud_showMultCount.Value;

            l_showMult1.Text = $"0x{start.ToString("X2")}";
            l_showMult2.Text = $"显示速度：        {frame.Frequency.ToString("f2")} Hz";
            l_showMult3.Text = $"显示单帧时间：  {frame.ExposureTime_ms.ToString("f2")} ms";
            l_showMult4.Text = $"显示总时间：     {(frame.ExposureTime_ms / 1000.0 * (int)count).ToString("f2")} s";
        }
        //多张图像连续播放
        private void b_showMult_Click(object sender, EventArgs e)
        {
            try
            {
                byte start = (byte)((int)nud_showMultStart.Value - 1);
                ProjectorFrame frame = new ProjectorFrame((int)nud_showMultFrequency.Value);
                byte count = (byte)nud_showMultCount.Value;

                tool.Send(tool.GetData_ContinuousDisplayImage(start, frame, count));
            }
            catch (Exception ex)
            {
                Log.SaveError(ex, $"投影仪多张图片播放异常，{ex.Message}", LogType.Run);
            }
        }
        //标定时投影仪参数
        private void b_calibration_Click(object sender, EventArgs e)
        {
            try
            {
                ProjectorConTrigger temp = new ProjectorConTrigger();
                temp.Start = (byte)((int)nud_showMultStart.Value - 1);
                temp.Frame = new ProjectorFrame((int)nud_showMultFrequency.Value);
                temp.Count = (byte)nud_showMultCount.Value;
                tool.Param.calibrationParam = temp;
                tool.Save();
            }
            catch (Exception ex)
            {
                Log.SaveError(ex);
            }
        }
        //重建时投影仪参数
        private void b_reconstruct_Click(object sender, EventArgs e)
        {
            try
            {
                ProjectorConTrigger temp = new ProjectorConTrigger();
                temp.Start = (byte)((int)nud_showMultStart.Value - 1);
                temp.Frame = new ProjectorFrame((int)nud_showMultFrequency.Value);
                temp.Count = (byte)nud_showMultCount.Value;
                tool.Param.reconstructParam = temp;
                tool.Save();
            }
            catch (Exception ex)
            {
                Log.SaveError(ex);
            }
        }
        #endregion

        #region 杂项
        /// <summary>
        /// 获取自定义图片索引名字，Image序号(十六进制)
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        private string GetImageName(int index)
        {
            return $"Image{(index + 1).ToString().PadLeft(2, '0')}(0x{index.ToString("X2")})";
        }
        /// <summary>
        /// 获取全部自定义图片索引名字
        /// </summary>
        /// <returns></returns>
        private string[] GetImageNames()
        {
            string[] names = new string[256];
            for (int i = 0; i < 256; i++)
            {
                names[i] = GetImageName(i);
            }
            return names;
        }
        /// <summary>
        /// 获取父窗口
        /// </summary>
        /// <param name="control"></param>
        /// <param name="MaxGet"></param>
        /// <returns></returns>
        private Control GetParent(Control control, int MaxGet = 1)
        {
            if (control.Parent == null)
                return control;
            else if (MaxGet == 1)
                return control.Parent;
            else
                return GetParent(control.Parent, MaxGet - 1);
        }

        //定时器
        private void timer1_Tick(object sender, EventArgs e)
        {
            RefreshPort(false);
        }
        #endregion
    }
}
